package hk.edu.polyu.comp.motioncapture.testing;

import hk.edu.polyu.comp.motioncapture.point.*;
import hk.edu.polyu.comp.motioncapture.collection.*;

import java.util.Iterator;
import java.util.Random;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class TestGiftWrapping {

	protected Shell shell;

	private Frame points;
	private Frame pointsBound;
	private Point initPoint;
	private int pointCounter;
	private String message;

	/**
	 * Launch the application
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			TestGiftWrapping window = new TestGiftWrapping();
			window.open();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * Open the window
	 */
	public void open() {
		final Display display = Display.getDefault();

		points = new Frame();
		pointsBound = new Frame();
		pointCounter = 0;
		message = "";

		createContents();
		shell.open();
		shell.layout();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch())
				display.sleep();
		}
	}

	/**
	 * Create contents of the window
	 */
	protected void createContents() {
		shell = new Shell();
		shell.setLayout(new FillLayout());
		shell.setSize(400, 400);
		shell.setText("Test Gift Wrapping Algorithm");

		final Composite composite = new Composite(shell, SWT.NONE);
		composite.setLayout(new GridLayout());

		final Canvas canvas = new Canvas(composite, SWT.NONE);
		canvas.addMouseListener(new MouseAdapter() {
			public void mouseDown(final MouseEvent e) {
				if (pointCounter == 0) {
					message = "";
					points = new Frame();
					pointsBound = new Frame();

					Random rand = new Random(System.currentTimeMillis());
					for (int i = 0; i < 80; i++) {
						Point pt = new Point(rand.nextDouble() * 320 + 20, rand
								.nextDouble() * 320 + 20);
						points.add(pt);
						// System.out.println("" + pt);
					}

					// Frame box = DimensionGeometry.giftWrappingBound(points);
					// System.out.println("\nBox:");
					// for (Point pt : box.getPointArray()) {
					// System.out.println("" + pt);
					// }
				} else {
				}

				Frame ptBound = new Frame();
				Frame ptTemp = new Frame();
				Iterator<Point> itPt = null;
				Point pt = null, initPt = null;
				Point leftPt = null, rightPt = null;
				Point lastPt = null;
				double rightAngle = 0, currentAngle = 0;
				int ptCount = 0;

				// Gift Wrapping Algorithm to find the bounding rectangle
				// 1. Find leftmost point
				double minX = Double.MAX_VALUE;

				itPt = points.iterator();
				while (itPt.hasNext()) {
					pt = itPt.next();
					ptTemp.add(pt); // Move all points to the temp list
					if (pt.getX() < minX) {
						minX = pt.getX();
						leftPt = pt;
					}
				}
				if (leftPt == null) {
					return;
				}

				initPt = leftPt;
				initPoint = initPt;
				lastPt = initPt.add(new Point(0, -1));

				// 2. Find a point such that all other points are to the right
				// of the
				// line
				boolean done = false;
				// Go thru every possible points
				while (ptTemp.size() > 0 && !done) {
					rightPt = null;
					itPt = ptTemp.iterator();
					while (itPt.hasNext()) {
						pt = itPt.next();
						if (pt != leftPt) {
							if (rightPt == null) {
								rightPt = pt;
								rightAngle = DimensionGeometry.polarAngle(
										lastPt, leftPt, pt);
							} else {
								currentAngle = DimensionGeometry.polarAngle(
										lastPt, leftPt, pt);
								if (currentAngle < rightAngle) {
									rightPt = pt;
									rightAngle = currentAngle;
									message = String
											.format(
													"rightAngle: %3.0f  -  1st angle: %3.0f  -  2nd angle: %3.0f",
													Math.toDegrees(rightAngle),
													Math
															.toDegrees(DimensionGeometry
																	.polarAngle(
																			lastPt,
																			leftPt)),
													Math
															.toDegrees(DimensionGeometry
																	.polarAngle(
																			leftPt,
																			pt)));
								}
							}
						}
					}
					// Add the point to list and move to other point
					if (rightPt != null) {
						ptBound.add(rightPt);
						ptTemp.remove(rightPt);

						ptCount++;
						if (ptCount > pointCounter) {
							pointCounter++;

							done = true;
						}

						if (rightPt == initPt) {
							pointCounter = 0;
							message += "   Done";

							done = true;
						} else {
							lastPt = leftPt;
							leftPt = rightPt;
							// message = String.format("rightAngle: %3.0f'",
							// Math
							// .toDegrees(rightAngle));
						}

					} else {
						pointCounter = 0;
						message = "Done";
						done = true;
					}
				}

				pointsBound = ptBound;

				canvas.redraw();
			}
		});
		canvas.addPaintListener(new PaintListener() {
			public void paintControl(final PaintEvent arg0) {
				Point lastPoint = initPoint;

				GC gc = arg0.gc;

				Color blackColor = new Color(shell.getDisplay(), new RGB(0, 0,
						0));
				Color whiteColor = new Color(shell.getDisplay(), new RGB(255,
						255, 255));
				Color redColor = new Color(shell.getDisplay(), new RGB(255, 0,
						0));
				Color greenColor = new Color(shell.getDisplay(), new RGB(0,
						255, 0));
				Color blueColor = new Color(shell.getDisplay(), new RGB(0, 0,
						255));

				gc.setForeground(redColor);
				gc.setBackground(whiteColor);
				gc.fillRectangle(0, 0, canvas.getBounds().width, canvas
						.getBounds().height);
				// System.out.println("Bound:" + canvas.getBounds());

				gc.setBackground(greenColor);
				for (Point pt : points.getPointArray()) {
					gc.fillOval((int) pt.getX() - 2, (int) pt.getY() - 2, 4, 4);
				}

				// Frame gw = DimensionGeometry.giftWrappingBound(points);

				gc.setForeground(blackColor);
				gc.setBackground(redColor);
				for (Point pt : pointsBound.getPointArray()) {
					gc.fillOval((int) pt.getX() - 2, (int) pt.getY() - 2, 4, 4);
					if (lastPoint != null) {
						gc.drawLine((int) lastPoint.getX(), (int) lastPoint
								.getY(), (int) pt.getX(), (int) pt.getY());
						lastPoint = pt;
					}
				}

				gc.setForeground(blackColor);
				gc.setBackground(whiteColor);
				gc.drawString(message, 0, 0);

				gc.setBackground(blueColor);
				if (initPoint != null)
					gc.fillOval((int) initPoint.getX() - 2, (int) initPoint
							.getY() - 2, 4, 4);

				gc.dispose();
			}
		});
		canvas.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
		//
	}

}
